#pragma once

#include <algorithm>
#include <functional>

#include "tchar.h"

namespace gtl
{

namespace string
{

inline bool is_space(gtl::tchar c)
{
	return _istspace(c) || c == _T(' ') || c == _T('\t') || c == _T('\r') || c == _T('\n');
}

static gtl::tchar* _ltrim(gtl::tchar* str)
{
	if(!str || !*str)
		return 0;

	while(str && *str)
	{
		if(is_space(*str))
			++str;
		else
			break;
	}

	return str;
}

static gtl::tchar* _rtrim(gtl::tchar* str)
{
	return _tcsrev(_ltrim(_tcsrev(str)));
}

static gtl::tchar* _trim(gtl::tchar* str)
{
	return _rtrim(_ltrim(str));
}

static const gtl::tchar* skip_whitespace(const gtl::tchar* p)
{
	if(!p || !*p)
	{
		return 0;
	}
	while(p && *p)
	{
		if(is_space(*p))
			++p;
		else
			break;
	}

	return p;
}

static gtl::tchar* ltrim(gtl::tchar* str, const gtl::tchar* charlist = _T(" \t\r\n"))
{
	if(!str || !*str || !charlist || !*charlist)
	{
		return 0;
	}

	const gtl::tchar* skip = charlist;
	gtl::tchar* q = str;

	while(str && *str)
	{
		q = str;
		skip = charlist;
		while(skip && *skip)
		{
			if(*q == *skip)
				++q;
			++skip;
		}

		if(str == q)
			break;
		else
			str = q;
	}

	return str;
}

static gtl::tchar* rtrim(gtl::tchar* str, const gtl::tchar* charlist = _T(" \t\r\n"))
{
	if(!str || !*str || !charlist || !*charlist)
	{
		return _T("");
	}

	return _tcsrev(ltrim(_tcsrev(str), charlist));
}

static gtl::tchar* trim(gtl::tchar* str, const gtl::tchar* charlist = _T(" \t\r\n"))
{
	return rtrim(ltrim(str, charlist));
}

static gtl::tstring ltrim(const gtl::tstring& str)   
{
	using namespace std;

	gtl::tstring result = str;
	gtl::tstring::iterator ite = find_if(result.begin(), result.end(), not1(ptr_fun(is_space)));   
    result.erase(result.begin(), ite);  

    return result;   
}   

static gtl::tstring rtrim(gtl::tstring& str)   
{
	using namespace std;

	gtl::tstring result = str;
	gtl::tstring::reverse_iterator ite = find_if(result.rbegin(), result.rend(), not1(ptr_fun(is_space)));   
    result.erase(ite.base(), result.end());  
   
	return result;   
}   

static gtl::tstring trim(gtl::tstring& str)   
{   
	gtl::tstring result = ltrim(rtrim(str));   
    return result;
}   

} // end namespace string

} // end namespace gtl